package com.ssy.lingxi.pay.callback;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConfig;
import com.alipay.api.internal.util.AlipaySignature;
import com.ssy.lingxi.common.constant.order.OrderPaymentParameterEnum;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.order.api.feign.OrderFeignService;
import com.ssy.lingxi.order.api.model.vo.request.OrderPayCallbackFeignVO;
import com.ssy.lingxi.pay.api.common.ServiceTypeEnum;
import com.ssy.lingxi.pay.common.AliPayResultEnum;
import com.ssy.lingxi.pay.model.assetAccount.AliPayAttachInfo;
import com.ssy.lingxi.pay.model.dto.ParameterCacheDTO;
import com.ssy.lingxi.pay.service.ICreditService;
import com.ssy.lingxi.pay.service.INotifyRecordService;
import com.ssy.lingxi.pay.service.IPayCacheService;
import com.ssy.lingxi.pay.service.assetAccount.IMemberAssetAccountService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 支付宝回调统一入口
 *
 * @author lqa
 * @version 2.0.0
 * @date 2021/11/2
 */
@RestController
@RequestMapping("/pay/aliPay")
public class AliPayController {
    private static final Logger logger = LoggerFactory.getLogger(WeChatController.class);

    @Resource
    private INotifyRecordService notifyRecordService;

    @Resource
    private IPayCacheService payCacheService;

    @Resource
    private IMemberAssetAccountService memberAssetAccountService;

    @Resource
    private OrderFeignService orderFeignService;

    @Resource
    private ICreditService creditService;

    /**
     * 支付通知接口
     * 1. 首先记录支付宝流水
     * 2. 进行业务操作
     */
    @RequestMapping(value = "/notify", method = RequestMethod.POST)
    @ResponseBody
    public void notify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        logger.info("------------支付宝支付回调通知--------------");
        //读取参数
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        logger.info("通知内容====={}", params.toString());
        logger.info("支付宝回调,sign:{},trade_status:{},参数:{}", params.get("sign"), params.get("trade_status"), params.toString());
        //验签
        //验证回调的正确性,是不是支付宝发的.并且要避免重复通知.
        params.remove("sign_type");    //remove这里看源码会发现，移不移除都没什么差，验签时会自动移除
        boolean validation = false;
        String result = "false";
        AlipayConfig alipayConfig = new AlipayConfig();
        try {
            //解析附加信息
            String attachStr = params.get("body");
            AliPayAttachInfo aliPayAttachInfo = payCacheService.deserializeObject(attachStr, AliPayAttachInfo.class);
            Integer payType = aliPayAttachInfo.getPayType();              //支付方式
            Long memberId = aliPayAttachInfo.getMemberId();               //会员id
            Long memberRoleId = aliPayAttachInfo.getMemberRoleId();       //会员角色id
            String serviceType = aliPayAttachInfo.getServiceType();       //服务类型p
            String attach = aliPayAttachInfo.getAttach();                 //附加信息
            String nonce = aliPayAttachInfo.getNonce();                   //用于缓存的随机字符串

            //从缓存中获取支付参数
            List<ParameterCacheDTO> parameters = payCacheService.findPayParameters(memberId, memberRoleId, payType, nonce);

            parameters.forEach(p -> {
                if (p.getCode().equals(OrderPaymentParameterEnum.ALIPAY_APP_ID.getCode())) {
                    alipayConfig.setAppId(p.getValue());
                    logger.info("缓存appId => " + p.getValue());
                } else if (p.getCode().equals(OrderPaymentParameterEnum.ALIPAY_PUBLIC_KEY.getCode())) {
                    alipayConfig.setAlipayPublicKey(p.getValue());
                    logger.info("缓存alipayPublicKey => " + p.getValue());
                } else if (p.getCode().equals(OrderPaymentParameterEnum.APP_ALIPAY_PRIVATE_KEY.getCode())) {
                    alipayConfig.setPrivateKey(p.getValue());
                    logger.info("缓存apiKey => " + p.getValue());
                } else {
                    logger.error("支付宝支付读取缓存数据错误：code => " + p.getCode() + " , value => " + p.getValue());
                }
            });
            //调用SDK验证签名
            validation = AlipaySignature.rsaCheckV2(params, alipayConfig.getAlipayPublicKey(), alipayConfig.getCharset(), alipayConfig.getSignType());
            logger.info("验签结果：{}",validation);
            if (validation) {
                //TODO 根据业务需要进行处理
                //商户订单号
                String out_trade_no = params.get("out_trade_no");
                //支付宝交易号
                String trade_no = params.get("trade_no");
                //新增交易记录
                notifyRecordService.saveAliPayNotifyRecord(params);
                //判断是否支付成功
                if (AliPayResultEnum.TRADE_SUCCESS.getSubCode().equals(params.get("trade_status"))) {
                    //回调业务方法
                    if (ServiceTypeEnum.Pay_Recharge.getCode().equals(serviceType)) {
                        memberAssetAccountService.payNotify(out_trade_no, trade_no);
                        logger.info(ServiceTypeEnum.Pay_Recharge.getMessage() + ":==========订单号：" + out_trade_no + "通知成功");
                    } else if (ServiceTypeEnum.Pay_Credit.getCode().equals(serviceType)) {
                        creditService.confirmRepaySucceed(out_trade_no, trade_no);
                        logger.info(ServiceTypeEnum.Pay_Credit.getMessage() + ":==========订单号：" + out_trade_no + "通知成功");
                    } else if (ServiceTypeEnum.Order_Pay.getCode().equals(serviceType)) {
                        OrderPayCallbackFeignVO orderPayCallbackFeignVO = new OrderPayCallbackFeignVO();
                        orderPayCallbackFeignVO.setTradeNo(out_trade_no);
                        orderPayCallbackFeignVO.setAttach(attach);
                        orderPayCallbackFeignVO.setPaySuccess(true);
                        Wrapper<Void> orderCallbackResult = orderFeignService.orderPayCallback(orderPayCallbackFeignVO);
                        logger.info(ServiceTypeEnum.Order_Pay.getMessage() + ":==========订单号：" + out_trade_no + " attach：" + attach + " , 支付成功通知结果" + orderCallbackResult.getMessage());
                    } else {
                        logger.error("==========订单号：" + out_trade_no + "通知失败，未找到对应的服务");
                    }
                } else {
                    if (ServiceTypeEnum.Order_Pay.getCode().equals(serviceType)) {
                        OrderPayCallbackFeignVO orderPayCallbackFeignVO = new OrderPayCallbackFeignVO();
                        orderPayCallbackFeignVO.setTradeNo(out_trade_no);
                        orderPayCallbackFeignVO.setAttach(attach);
                        orderPayCallbackFeignVO.setPaySuccess(false);
                        Wrapper<Void> orderCallbackResult = orderFeignService.orderPayCallback(orderPayCallbackFeignVO);
                        logger.info(ServiceTypeEnum.Order_Pay.getMessage() + ":==========订单号：" + out_trade_no + " attach：" + attach + " , 支付失败通知结果" + orderCallbackResult.getMessage());
                    }
                }
                result = "success";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        response.setContentType("text/html;charset=" + alipayConfig.getCharset());
        response.setCharacterEncoding(alipayConfig.getCharset());
        response.getWriter().write(result);// 直接将完整的表单html输出到页面
        response.getWriter().flush();
        response.getWriter().close();
    }
}


/*    *//**
 * 交易状态,新版支付接口回调不返回trade_status
 *
 * @param out_trade_no
 * @param trade_no
 * @return 只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功。
 * 注意：
 * 状态 TRADE_SUCCESS 的通知触发条件是商户签约的产品支持退款功能的前提下，买家付款成功；
 * 交易状态 TRADE_FINISHED 的通知触发条件是商户签约的产品不支持退款功能的前提下，买家付款成功；或者，商户签约的产品支持退款功能的前提下，交易已经成功并且已经超过可退款期限。
 * <p>
 * 只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功。
 * 注意：
 * 状态 TRADE_SUCCESS 的通知触发条件是商户签约的产品支持退款功能的前提下，买家付款成功；
 * 交易状态 TRADE_FINISHED 的通知触发条件是商户签约的产品不支持退款功能的前提下，买家付款成功；或者，商户签约的产品支持退款功能的前提下，交易已经成功并且已经超过可退款期限。
 * <p>
 * 只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功。
 * 注意：
 * 状态 TRADE_SUCCESS 的通知触发条件是商户签约的产品支持退款功能的前提下，买家付款成功；
 * 交易状态 TRADE_FINISHED 的通知触发条件是商户签约的产品不支持退款功能的前提下，买家付款成功；或者，商户签约的产品支持退款功能的前提下，交易已经成功并且已经超过可退款期限。
 * <p>
 * 只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功。
 * 注意：
 * 状态 TRADE_SUCCESS 的通知触发条件是商户签约的产品支持退款功能的前提下，买家付款成功；
 * 交易状态 TRADE_FINISHED 的通知触发条件是商户签约的产品不支持退款功能的前提下，买家付款成功；或者，商户签约的产品支持退款功能的前提下，交易已经成功并且已经超过可退款期限。
 * <p>
 * 只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功。
 * 注意：
 * 状态 TRADE_SUCCESS 的通知触发条件是商户签约的产品支持退款功能的前提下，买家付款成功；
 * 交易状态 TRADE_FINISHED 的通知触发条件是商户签约的产品不支持退款功能的前提下，买家付款成功；或者，商户签约的产品支持退款功能的前提下，交易已经成功并且已经超过可退款期限。
 *//*
    public String selectTradeStatus(String out_trade_no, String trade_no, AlipayConfig alipayConfig) {
        try {
            //固定配置
            alipayConfig.setServerUrl(AliPayConfig.gatewayUrl);
            AlipayClient alipayClient = null;
            try {
                alipayClient = new DefaultAlipayClient(alipayConfig);
            } catch (AlipayApiException e) {
                e.printStackTrace();
            }
            //统一收单线下交易查询对象:AlipayTradeQueryRequest
            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
            //自定义请求参数
            AlipayTradeQueryModel model = new AlipayTradeQueryModel();
            model.setOutTradeNo(out_trade_no);                               //商户订单号
            model.setTradeNo(trade_no);                               //支付宝交易号
            //  model.setOrgPid(orgPid); //银行间联模式下有用，其它场景请不要使用
            request.setBizModel(model);
            AlipayTradeQueryResponse response = null;
            try {
                response = alipayClient.execute(request);
            } catch (AlipayApiException e) {
                e.printStackTrace();
            }

            //交易状态
            String trade_status = response.getTradeStatus();

            *//**
 * 只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功。
 * 注意：
 *     状态 TRADE_SUCCESS 的通知触发条件是商户签约的产品支持退款功能的前提下，买家付款成功；
 *     交易状态 TRADE_FINISHED 的通知触发条件是商户签约的产品不支持退款功能的前提下，买家付款成功；或者，商户签约的产品支持退款功能的前提下，交易已经成功并且已经超过可退款期限。
 *//*
            if (trade_status.equals("TRADE_SUCCESS") || trade_status.equals("TRADE_FINISHED")) {

                //do something


            } else if (trade_status.equals("TRADE_CLOSED")) {            //交易关闭,未付款交易超时关闭，或支付完成后全额退款

                //do something
            } else {
                logger.error("支付宝支付错误,商户订单号：{},支付宝交易号：{}", out_trade_no, trade_no);
                return ServerResponse.createByErrorMessage("支付宝支付回调错误！");
            }

        } catch (AlipayApiException e) {
            logger.error("支付宝查询订单状态异常", e);
        }
        return ServerResponse.createByError();

    }*/

